﻿using System;
using System.Linq;
using System.ServiceProcess;

namespace unTroublemaker.Conditions
{
    public class ServiceCondition : SpecificationItemBase
    {
        private readonly bool _expectedRunningStatus;
        private readonly string _expectedStartupType;
        private readonly TestConditions _test;
        private readonly string _name;

        private enum TestConditions
        {
            RunningStatus,
            StartupType
        }
        private ServiceCondition(string name, bool expectedValue)
        {
            _test = TestConditions.RunningStatus;
            _expectedRunningStatus = expectedValue;
            _name = name;
        }

        private ServiceCondition(string name, string expectedValue)
        {
            _expectedStartupType = expectedValue;
            _name = name;
            _test = TestConditions.StartupType;
        }

        public static ISpecificationItem CheckRunning(string name, bool expectedValue)
        {
            return new ServiceCondition(name, expectedValue);
        }

        public static ISpecificationItem CheckStartupType(string name, string startupType)
        {
            return new ServiceCondition(name, startupType);
        }

        public static bool IsStartupType(string startupType)
        {
            var allowed = new[] {"manual", "automatic", "automatic (delayed start)", "disabled"};
            return allowed.Contains(startupType.ToLower());
        }

        protected override bool RunTest()
        {
            using (var sc = new ServiceController(_name))
            {
                if (_test == TestConditions.StartupType)
                    return TestStartupType(sc);

                return TestStatus(sc);
            }
        }

        private bool TestStatus(ServiceController sc)
        {

            if (_expectedRunningStatus && sc.Status == ServiceControllerStatus.Running)
                return true;
            if (_expectedRunningStatus == false && sc.Status != ServiceControllerStatus.Running)
                return true;

            var expectedStatus = _expectedRunningStatus ? "running" : "stopped";
            StatusMessage = string.Format("Expected service to be {0}, actual RunStatus = " + sc.Status, expectedStatus);
            return false;
        }

        private bool TestStartupType(ServiceController sc)
        {
            var actualStartupMode = ServiceHelper.GetStartupMode(sc.ServiceName);
            if (_expectedStartupType.Equals(actualStartupMode, StringComparison.CurrentCultureIgnoreCase))
                return true;

            StatusMessage = string.Format("Wrong startup type expected '{0}' actual '{1}'", _expectedStartupType,
                                          actualStartupMode);
            return false;
        }

        public override string DisplayName
        {
            get
            {
                if (_test == TestConditions.StartupType)
                    return "Checking startup type of " + _name + " = " + _expectedStartupType;

                return "Checking running RunStatus of " + _name + " = " + _expectedRunningStatus;
            }
        }
    }
}
